package com.obas.monitor;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.mina.core.session.IoSession;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

import com.obas.access.business.service.TestTaskItemAccessService;
import com.obas.access.business.service.TestcaseScriptAccessService;
import com.obas.business.common.vo.AtMessage;
import com.obas.business.common.vo.RunnableStep;
import com.obas.business.common.vo.TestContext;
import com.obas.business.scriptmanagement.service.ParameterizedScriptManagementService;
import com.obas.model.business.TestTaskItem;
import com.obas.monitor.manager.FeedManager;

import flex.messaging.io.amf.ASObject;

public class MessageProcessor {
   public static String RECORD = "record";
   public static String RECORD_DETAIL = "recordDetail";
   public static String RUN = "run";

   public static String IDE_STATE_KEY = "stateKey";

   public String state;
   public NioSocketAcceptor acceptor = null;
   private FeedManager feedManager;

   public void setFeedManager(FeedManager feedManager) {
      this.feedManager = feedManager;
   }

   private ParameterizedScriptManagementService parameterizedScriptManagementService;

   public void setParameterizedScriptManagementService(ParameterizedScriptManagementService parameterizedScriptManagementService) {
      this.parameterizedScriptManagementService = parameterizedScriptManagementService;
   }

   private TestcaseScriptAccessService testcaseScriptAccessService;

   public void setTestcaseScriptAccessService(TestcaseScriptAccessService testcaseScriptAccessService) {
      this.testcaseScriptAccessService = testcaseScriptAccessService;
   }

   private TestTaskItemAccessService testTaskItemAccessService;

   public void setTestTaskItemAccessService(TestTaskItemAccessService testTaskItemAccessService) {
      this.testTaskItemAccessService = testTaskItemAccessService;
   }

   public void processMessage(IoSession session, Object msg) {
      try {
         exeMessage(session, msg);

      } catch (Exception e) {
        e.printStackTrace();
      }
   }

   public void stopAut(String pageId) {
      sendStopAutMsg(pageId);
      TestContextManager.removeTestContext(pageId);
   }

   //for html
   public void beginRecord(String pageId) {
      sendBeginRecordMsg(pageId);
   }

   //for html
   public void endRecord(String pageId) {
      sendEndRecordMsg(pageId);
   }

   public void startPlay(String pageId) {
      sendPlayMsg(pageId);
   }

   public void getTreeRoot(String pageId) {
      sendGetTreeRootMsg(pageId);
   }

   public void toggleInspectFrame(String pageId, AtMessage msg) {
      sendToggleInspectFrameMsg(pageId, msg);
   }

   public void toggleInspectMode(String pageId, AtMessage msg) {
      sendToggleInspectModeMsg(pageId, msg);
   }

   public void getTreeChildren(String pageId, AtMessage msg) {
      sendGetTreeChildrenMsg(pageId, msg);
   }

   public void getProperties(String pageId, AtMessage msg) {
      sendGetPropertiesMsg(pageId, msg);
   }

   public void changePrefs(boolean genVerboseLocators, boolean genLocatorsWithId, boolean recordDetailed) {
      Map<String, Boolean> param = new HashMap<String, Boolean>();
      param.put("genVerboseLocators", genVerboseLocators);
      param.put("genLocatorsWithId", genLocatorsWithId);
      param.put("recordDetailed", recordDetailed);
//      session.write(new AtMessage(2, AtCommand.PrefsChange, param));
   }

   public void stopServer() {
      dispose();
   }

   private void dispose() {
      if (acceptor != null) {
         acceptor.dispose();
         acceptor = null;
      }
   }

   public void exeMessage(IoSession session, Object message) {
      if (message instanceof String && ((String)message).equals("#")) {
      }
      else if (message instanceof AtMessage) {
         AtMessage msg = (AtMessage)message;
         curMsgId = msg.getId();
         ASObject p = (ASObject)(msg.getParam());
         String pageid = (p != null)? p.get("pageId") + "" : "";
         switch (msg.getCommand()) {
            case AtCommand.RecordingStateChange:
               exeRecordingStateChange(pageid, msg, session);
               break;
            case AtCommand.Connect:
               exeConnected(pageid, msg, session);
               break;
            case AtCommand.OK:
               break;
            case AtCommand.ERROR:
               exeError(pageid, msg);
               break;
            case AtCommand.EventRecorded:
            case AtCommand.Verification:
                parameterizedScriptManagementService.record(msg);
               feedManager.sendMsg(msg, pageid);
               break;
            case AtCommand.ObjectHover:
            case AtCommand.GetTreeRoot:
            case AtCommand.GetTreeChildren:
            case AtCommand.GetProperties:
               feedManager.sendMsg(msg, pageid);
               break;
            case AtCommand.ExecMethod:
            case AtCommand.GetProperty:
               exeResult(pageid, msg);
               break;
            default:
               break;
         }
      }
   }

   public void sendStopAutMsg(String pageId) {
     TestContext context = TestContextManager.getTestContext(pageId);
     context.session.write(new AtMessage(genMsgId(), AtCommand.WindowClosed, null));
   }

   public void sendBeginRecordMsg(String pageId) {
      TestContext context = TestContextManager.getTestContext(pageId);
      context.ideState = AtCommand.ideRecordingReady;
      context.session.write(new AtMessage(genMsgId(), AtCommand.StartRecord, null));
   }

   public void sendEndRecordMsg(String pageId) {
      TestContext context = TestContextManager.getTestContext(pageId);
      context.ideState = AtCommand.ideConnectedIdle;
      context.session.write(new AtMessage(genMsgId(), AtCommand.StopRecord, null));
   }

   public void sendPlayMsg(String pageId) {
      TestContext context = TestContextManager.getTestContext(pageId);
      context.ideState = AtCommand.ideRunning;
      context.playError = false;
      context.playSuccess = true;
      runningMessage(pageId);
   }

   public void exeRecordingStateChange(String pageId, AtMessage msg, IoSession session) {
       session.write(new AtMessage(msg.getId(), AtCommand.OK, null));
       feedManager.sendMsg(msg, pageId);
   }

   public void exeConnected(String pageId, AtMessage msg, IoSession session ) {
       ASObject p = (ASObject)(msg.getParam());
       TestContext context = TestContextManager.getTestContext(pageId);
       synchronized (context) {
          if (context.ideState == 0) {
             context.ideState = AtCommand.ideConnectedIdle;
          }
          context.autURL = (String)(p.get("pageURL"));

          String appId = (String)(p.get("appId"));
          if (appId != null) {
              context.setAppSession(appId, session);
          }
          else {
              context.session = session;
          }
          Map<String, Object> param = new HashMap<String, Object>();
          param.put("ideState", context.ideState);
          session.write(new AtMessage(msg.getId(), AtCommand.OK, param));
          feedManager.sendMsg(new AtMessage(msg.getId(), AtCommand.Connect, null), pageId);
          if (context.ideState == AtCommand.ideRunning) {
              if (context.player != null) {
                  context.notifyAll();
              }
              else {
                  runningMessage(pageId);
              }
          }
       }
   }

   @SuppressWarnings("unchecked")
   public void exeResult(String pageId, AtMessage msg) {
      TestContext context = TestContextManager.getTestContext(pageId);
      synchronized (context) {
         if (context.ideState == AtCommand.ideRunning) {
            Map<String, Object> param = (Map<String, Object>)msg.getParam();
            Object result = param.get("result");
            if (msg.getCommand() == AtCommand.GetProperty) {
               RunnableStep step = context.runningStep;
               String value = ((Map<String, Object>)step.msg.getParam()).get("value") + "";
               if (value.equals(result + "")) {
                  context.playSuccess = true;
               }
               else {
                  context.playSuccess = false;
                  Map<String, Object> p = (Map<String, Object>)context.runningStep.msg.getParam();
                  p.put("newValue", result);
                  feedManager.sendMsg(new AtMessage(msg.getId(), AtCommand.ERROR, p), pageId);
               }
            }
            else {
               context.playSuccess = result != null;
            }

            context.notifyAll();
         }
      }
   }

   @SuppressWarnings("unchecked")
   public void exeError(String pageId, AtMessage msg) {
      TestContext context = TestContextManager.getTestContext(pageId);
      synchronized (context) {
          if (context.ideState == AtCommand.ideRunning) {
              context.playError = true;
              context.notifyAll();
              feedManager.sendMsg(new AtMessage(msg.getId(), AtCommand.ERROR, msg.getParam()), pageId);
              if (context.playType == TestContext.RUN) {
                 TestTaskItem taskItem = testTaskItemAccessService.findByTestTaskIdAndTestPlanItemId(context.testTaskId, context.testPlanItemId);
                 taskItem.setTestResult(false);
                 taskItem.setEndTime(new Date());
                 Map<String, Object> param = (Map<String, Object>)msg.getParam();
                 if (param.get("msg") != null) {
                     taskItem.setTestResultMessage(param.get("msg") + "");
                 }
                 testTaskItemAccessService.update(taskItem);
              }
          }
      }
   }

   private void sendGetPropertiesMsg(String appId, AtMessage msg) {
      TestContext context = TestContextManager.getTestContext(appId);
      context.session.write(msg);
   }

   public void sendGetTreeRootMsg(String appId) {
      TestContext context = TestContextManager.getTestContext(appId);
      context.session.write(new AtMessage(genMsgId(), AtCommand.GetTreeRoot, null));
   }

   public void sendGetTreeChildrenMsg(String appId, AtMessage msg) {
      TestContext context = TestContextManager.getTestContext(appId);
      context.session.write(msg);
   }

   public void sendToggleInspectFrameMsg(String appId, AtMessage msg) {
      TestContext context = TestContextManager.getTestContext(appId);
      context.session.write(msg);
   }

   public void sendToggleInspectModeMsg(String appId, AtMessage msg) {
      TestContext context = TestContextManager.getTestContext(appId);
      context.session.write(msg);
   }

   private void runningMessage(String pageId) {
      TestContext context = TestContextManager.getTestContext(pageId);
      MessagePlayer mp = new MessagePlayer(context, feedManager);
      context.player = new Thread(mp);
      context.script = parameterizedScriptManagementService.prepareParameterizedScript(context.parameterId, context.scriptId);
      context.player.start();
   }

   private int curMsgId = 2;
   private int genMsgId() {
       if (curMsgId < Integer.MAX_VALUE - 2) {
           curMsgId = curMsgId + 2;
       }
       else {
           curMsgId = 2;
       }
       return curMsgId;
   }

}
